Ya aprendimos a importar datos.

Ahora vamos a ver distintos elementos que necesitamos para procesarlos.

Algoritmos

Un algoritmo es un conjunto finito de instrucciones que, si se siguen rigurosamente, llevan a cabo una tarea específica.

Todos los algoritmos se componen de “partes” básicas que se utilizan para crear “partes” más complejas.

El tratamiento, análisis y modelado de datos lo haremos mediante algoritmos.

Variables y datos

Tipos de variables y operaciones

Enfoque teórico

Enfoque desde la programación

   

Asignación

# Una forma de hacer asignación
objeto <- "valor"
# Otra forma
objeto = "valor"
# Otro forma
"valor" -> objeto
# Ejemplos
pais = "Colombia"
departamentos = 32
trm = 4000.5
tenemos_mar = TRUE

Tipos de variables

  • Booleanos (lógicos)
    • VERDADERO
    • FALSO
objeto_nombrado_por_mi <- TRUE # Siempre con mayúsculas
objeto_nombrado_por_mi
## [1] TRUE
class(objeto_nombrado_por_mi)
## [1] "logical"
is.logical(objeto_nombrado_por_mi)
## [1] TRUE
  • Numéricos
    • Enteros
    • Reales
pi
## [1] 3.141593
objeto_nombrado_por_mi <- 0
objeto_nombrado_por_mi
## [1] 0
class(objeto_nombrado_por_mi)
## [1] "numeric"
is.numeric(objeto_nombrado_por_mi)
## [1] TRUE
  • Alfanuméricos: caracteres o cadenas de texto
objeto_nombrado_por_mi <- "hola mundo"
objeto_nombrado_por_mi
## [1] "hola mundo"
class(objeto_nombrado_por_mi)
## [1] "character"
is.character(objeto_nombrado_por_mi)
## [1] TRUE
  • Fechas
objeto_nombrado_por_mi <- "1969-07-21" # Recomendado: ISO 8601 para fechas
objeto_nombrado_por_mi
## [1] "1969-07-21"
class(objeto_nombrado_por_mi)
## [1] "character"
otro_objeto_distinto <- as.Date(objeto_nombrado_por_mi)
class(otro_objeto_distinto)
## [1] "Date"
  • NA
objeto_nombrado_por_mi <- NA # Siempre en mayúsculas NA
objeto_nombrado_por_mi
## [1] NA
class(objeto_nombrado_por_mi)
## [1] "logical"

Método is

cualquier_cosa <- TRUE
is.logical(cualquier_cosa)
## [1] TRUE
is.numeric(cualquier_cosa)
## [1] FALSE
is.character(cualquier_cosa)
## [1] FALSE

Método as

TRUE -> true_logico
true_logico
## [1] TRUE
class(true_logico)
## [1] "logical"
as.character(true_logico) -> true_char
true_char
## [1] "TRUE"
class(true_char)
## [1] "character"
1 -> uno_numeric
uno_numeric
## [1] 1
class(uno_numeric)
## [1] "numeric"
as.character(uno_numeric) -> uno_char
uno_char
## [1] "1"
class(uno_char)
## [1] "character"

Conversiones

Desde Hacia
logical numeric
logical character
numeric character
numeric Date
character Date

Operadores matemáticos

2+2
## [1] 4
5-2
## [1] 3
3*4
## [1] 12
5/4
## [1] 1.25
9 %% 2
## [1] 1
3 ** 3
## [1] 27
3 ^ 3
## [1] 27
log(10)
## [1] 2.302585
sqrt(16)
## [1] 4

Operadores para comparación

5 > 2
## [1] TRUE
5 < 2
## [1] FALSE
10 == 10
## [1] TRUE
10 == 9
## [1] FALSE
10 != 9
## [1] TRUE
10 >= 10
## [1] TRUE
10 <= 8
## [1] FALSE

Operadores lógicos

  • Conjunción (se cumplen ambas): &&
  • Disyunción (se cumple alguna): ||
  • Negación (lo contrario): !

Orden de las operaciones

  • PEMDAS
    • Paréntesis
    • Exponentes
    • Multiplicaciones / Divisiones
    • Adición / Sustracción

Variables

pi = 3.1415
radio = 3
area = pi * radio**2
area
## [1] 28.2735
round(area, 2)
## [1] 28.27
# Aplicado en una función
library("readxl")
ruta = "data/DataObesidad.xlsx"
hoja = "Obesidad"
read_xlsx(
  path = ruta, 
  sheet= hoja
) -> data_xlsx

Vectores, matrices, arreglos, listas y tablas

Un tipo especial de variables: factores

Son vectores numéricos enmascarados como caracteres. Se usan para crear grupos usando clasificaciones o codificaciones de las variables de interés. Estos factores pueden o no tener un orden.

Ejemplos: estrato socioeconómico, nivel de estudios, mes, sexo, localidad.

Vectores

1:5
## [1] 1 2 3 4 5
letters
##  [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
## [20] "t" "u" "v" "w" "x" "y" "z"
LETTERS
##  [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
## [20] "T" "U" "V" "W" "X" "Y" "Z"
c(1, 3, 2, 15, 4, 0, 0, 0, 1)
## [1]  1  3  2 15  4  0  0  0  1
seq(10, 100)
##  [1]  10  11  12  13  14  15  16  17  18  19  20  21  22  23  24  25  26  27  28
## [20]  29  30  31  32  33  34  35  36  37  38  39  40  41  42  43  44  45  46  47
## [39]  48  49  50  51  52  53  54  55  56  57  58  59  60  61  62  63  64  65  66
## [58]  67  68  69  70  71  72  73  74  75  76  77  78  79  80  81  82  83  84  85
## [77]  86  87  88  89  90  91  92  93  94  95  96  97  98  99 100
seq(10, 100, by = 5)
##  [1]  10  15  20  25  30  35  40  45  50  55  60  65  70  75  80  85  90  95 100
seq(10, 100, length.out = 8)
## [1]  10.00000  22.85714  35.71429  48.57143  61.42857  74.28571  87.14286
## [8] 100.00000

Factores

as.factor(letters)
##  [1] a b c d e f g h i j k l m n o p q r s t u v w x y z
## Levels: a b c d e f g h i j k l m n o p q r s t u v w x y z
estrato = c(2,3,4,1,3,6,5,2,3,4,1,2,3,4,6)
estrato
##  [1] 2 3 4 1 3 6 5 2 3 4 1 2 3 4 6
estrato.factor = factor(estrato)
estrato.factor
##  [1] 2 3 4 1 3 6 5 2 3 4 1 2 3 4 6
## Levels: 1 2 3 4 5 6
estrato.factor.ordenado = factor(estrato, levels=c(1,2,3,4,5,6))
estrato.factor.ordenado
##  [1] 2 3 4 1 3 6 5 2 3 4 1 2 3 4 6
## Levels: 1 2 3 4 5 6

Funciones sobre vectores

vector_logico <- c(TRUE,FALSE,FALSE,TRUE,FALSE)
vector_cualquiera <- seq(1, 100, by = 3)
un_vector <- c(1, 2, 3, 4, 5)
otro_vector <- c(6, 7, 8, 9, 10)
which(vector_logico) # me dice cuales son los verdaderos 
## [1] 1 4
length(vector_cualquiera) # me dice cuánto mide el vector
## [1] 34
c(un_vector, otro_vector) # concatena los vectores
##  [1]  1  2  3  4  5  6  7  8  9 10

Operaciones entre vectores

vector_numerico <- c(2, 4, 6, 8, 10)
vector_numeric_1 <- 1:3
vector_numeric_2 <- 3:5
vector_numerico > 3
## [1] FALSE  TRUE  TRUE  TRUE  TRUE
1:5 %in% 3:8
## [1] FALSE FALSE  TRUE  TRUE  TRUE
outer(vector_numeric_1, vector_numeric_2, "*")
##      [,1] [,2] [,3]
## [1,]    3    4    5
## [2,]    6    8   10
## [3,]    9   12   15
outer(vector_numeric_1, vector_numeric_2, ">")
##       [,1]  [,2]  [,3]
## [1,] FALSE FALSE FALSE
## [2,] FALSE FALSE FALSE
## [3,] FALSE FALSE FALSE

Operaciones entre vectores (conjuntos)

union(vector_numeric_1, vector_numeric_2)
## [1] 1 2 3 4 5
intersect(vector_numeric_1, vector_numeric_2)
## [1] 3
setdiff(vector_numeric_1, vector_numeric_2)
## [1] 1 2

Matrices

matrix(data = 1:12, nrow = 3)
##      [,1] [,2] [,3] [,4]
## [1,]    1    4    7   10
## [2,]    2    5    8   11
## [3,]    3    6    9   12
matrix(data = 1:12, nrow = 6)
##      [,1] [,2]
## [1,]    1    7
## [2,]    2    8
## [3,]    3    9
## [4,]    4   10
## [5,]    5   11
## [6,]    6   12
matrix(data = 1:12, ncol = 6)
##      [,1] [,2] [,3] [,4] [,5] [,6]
## [1,]    1    3    5    7    9   11
## [2,]    2    4    6    8   10   12
matrix(data = 1:12, nrow = 4)
##      [,1] [,2] [,3]
## [1,]    1    5    9
## [2,]    2    6   10
## [3,]    3    7   11
## [4,]    4    8   12
matrix(data = 1:12, nrow = 4, byrow = TRUE)
##      [,1] [,2] [,3]
## [1,]    1    2    3
## [2,]    4    5    6
## [3,]    7    8    9
## [4,]   10   11   12
matrix(data = seq(0, 9, length.out = 4), nrow = 2) -> mi_matriz
mi_matriz
##      [,1] [,2]
## [1,]    0    6
## [2,]    3    9

Operaciones sobre matrices

otra_matriz # Toca inventársela
mi_matriz*2 # Producto por un escalar
mi_matriz + otra_matriz # Suma de matrices
mi_matriz*otra_matriz # Producto celda por celda
mi_matriz %*% otra_matriz # Producto de matrices

Funciones sobre matrices

t(mi_matriz) #mi_matriz transpuesta
##      [,1] [,2]
## [1,]    0    3
## [2,]    6    9
diag(mi_matriz) #Diagonal de mi_matriz
## [1] 0 9
det(mi_matriz) # Determinante, debe dar un número
## [1] -18
solve(mi_matriz) # Matriz inversa, sólo se puede con matrices cuadradas de determinante distinto de cero
##            [,1]      [,2]
## [1,] -0.5000000 0.3333333
## [2,]  0.1666667 0.0000000
dim(mi_matriz) # Dimensión de mi matriz
## [1] 2 2

Bibliografía complementaria: Parte 1 Capítulo 2: Linear Algebra, del libro Deep Learning del MIT

Tablas

library("tidyverse")
iris
?iris
diamonds
?diamonds
mpg
?mpg

class(diamonds)
class(mpg)

str(diamonds)
str(mpg)

View(diamonds)
View(mpg)

Extracción [.

cuales_extraer <- c(1, 8, 6, 3) # Creo un vactor con las posiciones que deseo extraer
letters[cuales_extraer] # Extrae las letras 1, 8, 6, 3 del vector letters
## [1] "a" "h" "f" "c"
vector_numerico[vector_numerico > 3] # Extrae los valores mayores a 3 en vector_numerico
## [1]  4  6  8 10
un_vector[1] # Extrae el elemento #1 del vector un_vector
## [1] 1
mi_matriz[1,2] # Extrae el valor en la fila 1 columna 2 de mi_matriz
## [1] 6
mi_matriz[,1] # Extrae la primera columna de mi_matriz
## [1] 0 3
mi_matriz[2,] # Extrae la segunda fila mi_matriz
## [1] 3 9
diamonds[,8] # Extrae la fila 8 de diamonds
## # A tibble: 53,940 × 1
##        x
##    <dbl>
##  1  3.95
##  2  3.89
##  3  4.05
##  4  4.2 
##  5  4.34
##  6  3.94
##  7  3.95
##  8  4.07
##  9  3.87
## 10  4   
## # ℹ 53,930 more rows
diamonds["x"] # Extrae de diamonds la columna llamada "x"
## # A tibble: 53,940 × 1
##        x
##    <dbl>
##  1  3.95
##  2  3.89
##  3  4.05
##  4  4.2 
##  5  4.34
##  6  3.94
##  7  3.95
##  8  4.07
##  9  3.87
## 10  4   
## # ℹ 53,930 more rows
cuales_extraer = c("x","y","z") # Creo un vector de variables a extraer
diamonds[cuales_extraer] #Hago la extracción
## # A tibble: 53,940 × 3
##        x     y     z
##    <dbl> <dbl> <dbl>
##  1  3.95  3.98  2.43
##  2  3.89  3.84  2.31
##  3  4.05  4.07  2.31
##  4  4.2   4.23  2.63
##  5  4.34  4.35  2.75
##  6  3.94  3.96  2.48
##  7  3.95  3.98  2.47
##  8  4.07  4.11  2.53
##  9  3.87  3.78  2.49
## 10  4     4.05  2.39
## # ℹ 53,930 more rows

Ejemplo: Prueba T

A partir de la base de datos evaluacion, hagamos una prueba de hipótesis para testear si el puntaje obtenido en ciencias (variable ciencias) está influenciado/afectado por el sexo (variable sexo).

Nota: cuando una variable toma dos valores se puede recodificar como una variable dummy.

# Cargo los datos de evaluacion y lo guardo en un objeto llamado evaluacion_xlsx
read_xlsx(
  path = "data/evaluacion.xlsx", 
  sheet= "datos"
) -> evaluacion_xlsx
# Hago la prueba t
t.test(ciencias ~ sexo, data = evaluacion_xlsx) -> t_test_ciencias_sexo
# Llamo los resultados de la prueba t
t_test_ciencias_sexo
## 
##  Welch Two Sample t-test
## 
## data:  ciencias by sexo
## t = -0.81103, df = 37.626, p-value = 0.4224
## alternative hypothesis: true difference in means between group Femenino and group Masculino is not equal to 0
## 95 percent confidence interval:
##  -1.1161022  0.4777622
## sample estimates:
##  mean in group Femenino mean in group Masculino 
##                9.771739               10.090909

¿Qué podríamos extraer de este objeto?

str(t_test_ciencias_sexo)
## List of 10
##  $ statistic  : Named num -0.811
##   ..- attr(*, "names")= chr "t"
##  $ parameter  : Named num 37.6
##   ..- attr(*, "names")= chr "df"
##  $ p.value    : num 0.422
##  $ conf.int   : num [1:2] -1.116 0.478
##   ..- attr(*, "conf.level")= num 0.95
##  $ estimate   : Named num [1:2] 9.77 10.09
##   ..- attr(*, "names")= chr [1:2] "mean in group Femenino" "mean in group Masculino"
##  $ null.value : Named num 0
##   ..- attr(*, "names")= chr "difference in means between group Femenino and group Masculino"
##  $ stderr     : num 0.394
##  $ alternative: chr "two.sided"
##  $ method     : chr "Welch Two Sample t-test"
##  $ data.name  : chr "ciencias by sexo"
##  - attr(*, "class")= chr "htest"

Extraigamos el p-valor de la prueba.

t_test_ciencias_sexo["p.value"]
## $p.value
## [1] 0.4224486
t_test_ciencias_sexo[["p.value"]]
## [1] 0.4224486
# Otra forma
t_test_ciencias_sexo$p.value
## [1] 0.4224486

Podemos extraer partes de todos los objetos que tengamos en nuestro ambiente de trabajo.

Ejemplo: Modelo de regresión lineal

Ajustemos un modelo de regresión lineal simple usando como variable respuesta el puntaje obtenido en humanidades (variable humanidades) en función del puntaje obtenido en ciencias (variable ciencias).

lm(humanidades ~ ciencias, data = evaluacion_xlsx) -> modelo_humanidades_ciencias
modelo_humanidades_ciencias
## 
## Call:
## lm(formula = humanidades ~ ciencias, data = evaluacion_xlsx)
## 
## Coefficients:
## (Intercept)     ciencias  
##      1.3645       0.8656

summary(modelo_humanidades_ciencias)
## 
## Call:
## lm(formula = humanidades ~ ciencias, data = evaluacion_xlsx)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -3.0606 -1.1006 -0.0048  0.6411  3.1759 
## 
## Coefficients:
##             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)   1.3645     1.4660   0.931    0.357    
## ciencias      0.8656     0.1464   5.911 4.92e-07 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 1.267 on 43 degrees of freedom
## Multiple R-squared:  0.4483, Adjusted R-squared:  0.4355 
## F-statistic: 34.94 on 1 and 43 DF,  p-value: 4.92e-07

¿Qué podríamos extraer de este objeto?

str(summary(modelo_humanidades_ciencias))
## List of 11
##  $ call         : language lm(formula = humanidades ~ ciencias, data = evaluacion_xlsx)
##  $ terms        :Classes 'terms', 'formula'  language humanidades ~ ciencias
##   .. ..- attr(*, "variables")= language list(humanidades, ciencias)
##   .. ..- attr(*, "factors")= int [1:2, 1] 0 1
##   .. .. ..- attr(*, "dimnames")=List of 2
##   .. .. .. ..$ : chr [1:2] "humanidades" "ciencias"
##   .. .. .. ..$ : chr "ciencias"
##   .. ..- attr(*, "term.labels")= chr "ciencias"
##   .. ..- attr(*, "order")= int 1
##   .. ..- attr(*, "intercept")= int 1
##   .. ..- attr(*, "response")= int 1
##   .. ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 
##   .. ..- attr(*, "predvars")= language list(humanidades, ciencias)
##   .. ..- attr(*, "dataClasses")= Named chr [1:2] "numeric" "numeric"
##   .. .. ..- attr(*, "names")= chr [1:2] "humanidades" "ciencias"
##  $ residuals    : Named num [1:45] 1.446 1.396 -1.266 0.787 0.103 ...
##   ..- attr(*, "names")= chr [1:45] "1" "2" "3" "4" ...
##  $ coefficients : num [1:2, 1:4] 1.364 0.866 1.466 0.146 0.931 ...
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:2] "(Intercept)" "ciencias"
##   .. ..$ : chr [1:4] "Estimate" "Std. Error" "t value" "Pr(>|t|)"
##  $ aliased      : Named logi [1:2] FALSE FALSE
##   ..- attr(*, "names")= chr [1:2] "(Intercept)" "ciencias"
##  $ sigma        : num 1.27
##  $ df           : int [1:3] 2 43 2
##  $ r.squared    : num 0.448
##  $ adj.r.squared: num 0.435
##  $ fstatistic   : Named num [1:3] 34.9 1 43
##   ..- attr(*, "names")= chr [1:3] "value" "numdf" "dendf"
##  $ cov.unscaled : num [1:2, 1:2] 1.3382 -0.1326 -0.1326 0.0134
##   ..- attr(*, "dimnames")=List of 2
##   .. ..$ : chr [1:2] "(Intercept)" "ciencias"
##   .. ..$ : chr [1:2] "(Intercept)" "ciencias"
##  - attr(*, "class")= chr "summary.lm"

Extraigamos el \(R^2\) ajustado del modelo.

summary(modelo_humanidades_ciencias)$adj.r.squared
## [1] 0.4354905

Control flow

El control flow es un conjunto de funciones que permiten manejar las órdenes de manera estructurada y lógica. Las más importantes son:

?Control

Loops

Todos los lenguajes modernos de programación ofrecen una o más maneras de realizar operaciones iterativas. El poder repetir la misma acción una cantidad indefinida de veces es una de las grandes ventajas de realizar las tareas mediante programación.

## for

Sirve para crear tareas repetitivas de un número de pasos específico.

Uno de los usos más frecuentes de un ciclo for es la configuración de métodos de remuestreo (bootstraping).

#vamos a guardar en una lista los coeficientes de una regresión
coeficientes <- list()

# inicializo el ciclo for
for(i in 1:1000){
  #en cada paso
  
  # 1. saco una muestra de 30 estudiantes
  muestra <- sample_n(evaluacion_xlsx, 30)
  
  # 2. ajusto un modelo de regresión lineal
  lm(humanidades ~ ciencias, data = muestra) -> modelo
  
  # 3. extraigo y almaceno los coeficientes del modelo
  coeficientes[[i]] <- coefficients(modelo)
}

# grafico el comportamiento de los coeficientes
coeficientes %>% 
  transpose %>% 
  lapply(unlist) %>% 
  as_tibble() %>% 
  gather(key = coeficiente, value = valor) %>% 
  ggplot +
  aes(x = valor) + 
  geom_density() +
  facet_wrap(~coeficiente, nrow = 2,  scales = "free")

while

Sirve para crear tareas repetitivas que no sabemos después de cuántos pasos terminan. Requiere una inicialización cuidadosa.

Ejemplo: ¿Cuántos sobres tengo que comprar para llenar un álbum de 100 cromos?

# inicializo las condiciones de partida
album <- iteracion <- 0
# creo la condición lógica que permite ejecutar el proceso
aun_falta <- TRUE

# siempre que aun_falta siga siendo verdadero
while(aun_falta){
  # en cada ciclo
  
  # 1. actualizo en qué iteración voy
  iteracion <- iteracion + 1
  
  # 2. extraigo una muestra de 6 números ("compro un sobre con 6 cromos")
  sobre <- sample(100, 6)
  
  # 3.1 tomo el álbum
  # 3.2 le combino los cromos que obtuve
  # 3.3 ordeno los cromos de menor a mayor
  # 3.4 dejo valores únicos (quito cromos duplicados)
  # 3.5 actualizo el álbum
  album %>% c(sobre) %>% sort %>% unique -> album
  
  # 4. si tengo menos de 100 cromos es porque me falta
  length(album) < 100 -> aun_falta
}

# muestro el número de iteraciones
# es decir, cuántos sobres tuve que comprar
iteracion
## [1] 79

if, else

La estructura if sirve para ejecutar varias rutinas distintas dependiendo de una condición lógica. En caso de que sea necesario, es posible aplicar una rutina alterna con la estructura else.

Ejemplo: Prueba de normalidad.

Diversas pruebas y modelos estadísticos requieren verificar el supuesto de normalidad en los datos.

# cargo la base de datos del PGN y la almaceno en un objeto llamado pgn
read_xlsx(
  path = "data/Base de datos PGN 2024.xlsx", 
  sheet= "Data"
) -> pgn
# extraigo la variable Funcionamiento
# le hago un test de shapiro
# guardo los resultados de la prueba en un objeto llamado prueba_sw
pgn[["Funcionamiento"]] %>% shapiro.test() -> prueba_sw

# estructura condicional
if(prueba_sw$p.value > 0.05){
  # Si acepto la hipótesis de normalidad en la variable mpg
  # Hago una prueba t
  print("La variable Funcionamiento sigue una distribución normal")
} else {
  # Si rechazo la hipótesis de normalidad en la variable mpg
  # Hago una prueba Mann-Whitney-Wilcoxon
  print("La variable Funcionamiento no sigue una distribución normal")
}
## [1] "La variable Funcionamiento no sigue una distribución normal"